package com.boarsoft.flow.core;

import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import com.boarsoft.common.Util;
import com.boarsoft.flow.trace.FlowTrace;
import com.boarsoft.flow.trace.SimpleFlowTrace;
import com.boarsoft.serialize.JavaSerializer;
import com.boarsoft.serialize.ObjectSerializer;

public class SimpleFlowImpl implements SimpleFlow, Serializable {
	private static final long serialVersionUID = 6709908139537689244L;

	// 以下是流程的静态属性

	/** 流程定义ID */
	protected String flowId;
	/** 流程中文名 */
	protected String name;
	/** */
	protected String entry;
	/** 是否互斥 */
	protected boolean mutex = false;
	/** timeout <= 0 表示不计时 */
	protected long timeout;
	/** 版本号 */
	protected String ver;
	/** 反交易流程 */
	protected String revCode;
	/** 冲正类型（执行时机） */
	protected short revType = SimpleFlow.REV_TYPE_IGNORE;
	/** 冲正次数上限 */
	protected int revLimit = 3;

	// 以下是流程的动态属性（可持久化的项）

	/** 流程实例ID，注意setId()方法 */
	protected String id;
	/** 当前步骤 */
	protected ThreadLocal<String> stepTL = new ThreadLocal<>();
	/** 当前数据 */
	protected Object data;
	/** 当前状态 */
	protected short status = SimpleFlow.STATUS_NEW;
	/** 当前异常 */
	protected Throwable error;
	/** 开始时间 */
	protected long startTime;
	/** 结束时间 */
	protected long endTime;
	/** 耗时 */
	protected long time;
	/** 最晚结束时间（超时时间） */
	protected long deadline;
	/** 反交易流程入口 */
	protected String revEntry;
	/** 正交易实例ID（如果当前流程是反交易的话） */
	protected String revFor;
	/** 冲正次数 */
	protected int revTime;
	/** 冲正状态 */
	protected short revStatus = SimpleFlow.REV_NONE;
	/** 冲正异常 */
	protected Throwable revError;
	/** 执行流程的节点 */
	protected String addr;
	/** 采样率 */
	protected int traceRatio;
	/** 消息事件队列名 */
	protected String traceTarget;
	/** 调用率是否含数据 */
	protected boolean traceIo;

	// 以下是流程运行时变量，不需要持久化

	/** */
	public transient ObjectSerializer serializer = new JavaSerializer();
	/** 采样率 */
	protected transient AtomicInteger traceRating = new AtomicInteger(0);
	/** */
	protected transient volatile short flag = FLAG_GO;
	/** 此流程的父流程是谁 */
	protected transient String parent;
	/** */
	protected transient FlowTrace trace;
	/** 运行时附件 */
	protected transient Map<String, Object> attachments = new ConcurrentHashMap<>();

	public SimpleFlowImpl() {
	}

	public SimpleFlowImpl(String flowId) {
		this.flowId = flowId;
		trace = new SimpleFlowTrace(flowId);
	}

	public SimpleFlowImpl(String flowId, String flowExeId) {
		this.flowId = flowId;
		this.id = flowExeId;
		trace = new SimpleFlowTrace(flowId);
	}

	public SimpleFlow newInstance() {
		SimpleFlowImpl o = new SimpleFlowImpl(this.flowId);
		o.name = this.name;
		o.entry = this.entry;
		o.mutex = this.mutex;
		o.timeout = this.timeout;
		o.ver = this.ver;
		o.revCode = this.revCode;
		o.revType = this.revType;
		o.revLimit = this.revLimit;
		o.traceRatio = this.traceRatio;
		o.traceTarget = this.traceTarget;
		o.trace = new SimpleFlowTrace(flowId);
		return o;
	}

	public boolean hasParent() {
		return Util.strIsNotEmpty(parent);
	}

	@Override
	public void setId(String id) {
		this.id = id;
		this.trace.setId(id);
	}

	@Override
	public void setTraceRatio(int traceRatio) {
		this.traceRatio = traceRatio;
	}

	@Override
	public int getTraceRatio() {
		return traceRatio;
	}

	@Override
	public String getId() {
		return id;
	}

	@Override
	public boolean isMutex() {
		return mutex;
	}

	@Override
	public String getFlowId() {
		return flowId;
	}

	@Override
	public String toString() {
		return new StringBuilder().append(flowId).append("/").append(id).toString();
	}

	@Override
	public String getStep() {
		return stepTL.get();
	}

	@Override
	public void setStep(String step) {
		this.stepTL.set(step);
	}

	@Override
	public void setFlowId(String flowId) {
		this.flowId = flowId;
	}

	@Override
	public Object getData() {
		return data;
	}

	@Override
	public void setData(Object data) {
		this.data = data;
	}

	@Override
	public short getFlag() {
		return flag;
	}

	@Override
	public void setFlag(short flag) {
		this.flag = flag;
	}

	@Override
	public String getEntry() {
		return entry;
	}

	@Override
	public void setEntry(String entry) {
		this.entry = entry;
	}

	@Override
	public void setMutex(boolean mutex) {
		this.mutex = mutex;
	}

	@Override
	public Throwable getError() {
		return error;
	}

	@Override
	public void setError(Throwable error) {
		this.error = error;
	}

	@Override
	public long getTimeout() {
		return timeout;
	}

	@Override
	public void setTimeout(long timeout) {
		this.timeout = timeout;
	}

	@Override
	public long getDeadline() {
		return deadline;
	}

	@Override
	public void setDeadline(long deadline) {
		this.deadline = deadline;
	}

	@Override
	public long getStartTime() {
		return startTime;
	}

	@Override
	public void setStartTime(long startTime) {
		this.startTime = startTime;
	}

	@Override
	public String getVer() {
		return ver;
	}

	@Override
	public void setVer(String ver) {
		this.ver = ver;
	}

	@Override
	public boolean getMutex() {
		return mutex;
	}

	@Override
	public String getRevCode() {
		return revCode;
	}

	@Override
	public void setRevCode(String revCode) {
		this.revCode = revCode;
	}

	@Override
	public short getRevType() {
		return revType;
	}

	@Override
	public void setRevType(short revType) {
		this.revType = revType;
	}

	@Override
	public long getEndTime() {
		return endTime;
	}

	@Override
	public void setEndTime(long endTime) {
		this.endTime = endTime;
		this.trace.setEndTime(endTime);
	}

	@Override
	public long getTime() {
		return endTime - startTime;
	}

	@Override
	public String getRevEntry() {
		return revEntry;
	}

	@Override
	public void setRevEntry(String revEntry) {
		this.revEntry = revEntry;
	}

	@Override
	public short getStatus() {
		return status;
	}

	@Override
	public void setStatus(short status) {
		this.status = status;
		trace.setStatus(status);
	}

	@Override
	public String getRevFor() {
		return revFor;
	}

	@Override
	public void setRevFor(String revFor) {
		this.revFor = revFor;
	}

	@Override
	public int getRevLimit() {
		return revLimit;
	}

	@Override
	public void setRevLimit(int revLimit) {
		this.revLimit = revLimit;
	}

	@Override
	public int getRevTime() {
		return revTime;
	}

	@Override
	public void setRevTime(int revTime) {
		this.revTime = revTime;
	}

	@Override
	public short getRevStatus() {
		return revStatus;
	}

	@Override
	public void setRevStatus(short revStatus) {
		this.revStatus = revStatus;
	}

	@Override
	public Throwable getRevError() {
		return revError;
	}

	@Override
	public void setRevError(Throwable revError) {
		this.revError = revError;
	}

	@Override
	public String getAddr() {
		return addr;
	}

	@Override
	public void setAddr(String addr) {
		this.addr = addr;
	}

	public void setTime(long time) {
		this.time = time;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public FlowTrace getTrace() {
		return trace;
	}

	@Override
	public boolean isTracing() {
		return Util.strIsNotEmpty(traceTarget) && traceRatio > 0;
	}

	@Override
	public String getTraceTarget() {
		return traceTarget;
	}

	@Override
	public void setTraceTarget(String traceTarget) {
		this.traceTarget = traceTarget;
	}

	@Override
	public boolean isTraceIo() {
		return traceIo;
	}

	@Override
	public void setTraceIo(boolean traceIo) {
		this.traceIo = traceIo;
	}

	@Override
	public String getParent() {
		return parent;
	}

	@Override
	public void setParent(String parent) {
		this.parent = parent;
	}

	@Override
	public Map<String, Object> getAttachments() {
		return attachments;
	}

	@Override
	public void setAttachments(Map<String, Object> attachments) {
		this.attachments = attachments;
	}

}
